package com.edgardeng.utils;

import com.edgardeng.generator.entity.SQLDataSource;
import com.edgardeng.generator.entity.Table;
import freemarker.template.TemplateException;
import freemarker.template.TemplateExceptionHandler;
import freemarker.template.Template;
import com.edgardeng.generator.entity.ColumnEntity;
import com.edgardeng.generator.entity.TableEntity;
import org.apache.commons.configuration.Configuration;
import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.configuration.PropertiesConfiguration;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.WordUtils;

import java.io.*;
import java.util.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * 代码生成器   工具类
 */
public class GenUtils {


    public static void freemarkerGenDBDoc(List<Map<String, Object>> tableList, ZipOutputStream zip) {
        try {


            //封装模板数据
            Map<String, Object> tmplateData = new HashMap<>();
            tmplateData.put("tables", tableList);

            String fileName = "docs" + File.separator + "db" + File.separator + "db_.md"; //生成的文件地址
            String templateName = "db_doc.ftl"; // 模板名
            freemarkerTemp2File(templateName, tmplateData, fileName);

            File file = new File(fileName);

            byte[] buf = new byte[2 * 1024];

            System.out.println("generator file:" + file);

            int length = 0;

            zip.putNextEntry(new ZipEntry(fileName));
            System.out.println("generator in:" + fileName);
            FileInputStream in = new FileInputStream(file);
            while ((length = in.read(buf)) != -1) {
                zip.write(buf, 0, 0);
            }
            zip.closeEntry();
            in.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 生成代码
     *
     * @param table
     * @param columns
     * @param zip
     */
    public static void freemarkerGenCode(Table table, List<ColumnEntity> columns, ZipOutputStream zip, SQLDataSource dataSource) {
        //配置信息
        Configuration config = getConfig();
        boolean hasBigDecimal = false;
        boolean hasDate = false;

        //表信息
        TableEntity tableEntity = new TableEntity();
        tableEntity.setTableName(table.getName());
        tableEntity.setComment(table.getComment());
        //表名转换成Java类名
        String className = tableToJava(tableEntity.getTableName(), config.getString("tablePrefix"));
        tableEntity.setClassName(className);
        tableEntity.setLowClassName(StringUtils.uncapitalize(className));

        for (ColumnEntity columnEntity : columns) {
            //列名转换成Java属性名
            String attrName = columnToJava(columnEntity.getName());
            columnEntity.setAttrName(attrName);
            columnEntity.setAttrname(StringUtils.uncapitalize(attrName));

            //列的数据类型，转换成Java类型
            String attrType = config.getString(columnEntity.getType(), "unknowType");
            columnEntity.setAttrType(attrType);
            if (!hasBigDecimal && attrType.equals("BigDecimal")) {
                hasBigDecimal = true;
            }
            if (!hasDate && attrType.equals("Date")) {
                hasDate = true;
            }
        }
        tableEntity.setColumns(columns);

//        String mainPath = config.getString("mainPath");
//        mainPath = StringUtils.isBlank(mainPath) ? "com.edgardeng" : mainPath;
//
//        String module = config.getString("moduleName");
        String p_controller = config.getString("controllerPackage");
        String p_entity = config.getString("entityPackage");
        String p_mapper = config.getString("mapperPackage");
        String p_service = config.getString("servicePackage");
//        String p_configure = config.getString("configurePackage");
//
//        String dir_src = config.getString("srcDir");
//        String dir_res = config.getString("recDir");


        //封装模板数据
        Map<String, Object> map = new HashMap<>();
        map.put("tableName", tableEntity.getTableName());
        map.put("tableComment", tableEntity.getComment());

        map.put("pk", tableEntity.getPk());
        map.put("className", tableEntity.getClassName());
        map.put("classname", tableEntity.getLowClassName());
//        map.put("pathName", tableEntity.getClassname().toLowerCase());
        map.put("columns", tableEntity.getColumns());
        map.put("hasBigDecimal", hasBigDecimal);
        map.put("hasDate", hasDate);

        map.put("controllerPackage", p_controller);
        map.put("entityPackage", p_entity);
        map.put("mapperPackage", p_mapper);
        map.put("servicePackage", p_service);

        String packageName = dataSource.getPackageName();
        map.put("packageName", packageName);
        String packageCommon = packageName;
        int jIndex = packageName.indexOf("jupiter");
        if (jIndex > 0) {
            packageCommon = packageName.substring(0, jIndex) + "jupiter.common";
        }
        map.put("packageCommon", packageCommon);
        map.put("author", dataSource.getAuthor());
        map.put("date", DateUtils.format(new Date(), DateUtils.DATE_TIME_PATTERN));
        // 2 packageName
        String[] packageNames = dataSource.getPackageName().split("\\.");


        String mainDir = dataSource.getDir() + File.separator + "src" + File.separator + "main";
        String javaPackage = mainDir + File.separator + "java";
        String resPackage = mainDir + File.separator + "resources";

        for (String n : packageNames) {
            javaPackage = javaPackage + File.separator + n;
        }
        String moduleName = packageNames[packageNames.length-1]; // 最后一个是模块名
        map.put("moduleName", moduleName);

        String[] tmps = new String[]{
                "controller.ftl",
                "entity.ftl",
                "mapper.ftl",
                "mapperXml.ftl",
                "service.ftl",
                "serviceImpl.ftl",
                "ui_api.ftl",
                "ui_page.ftl",
        };
        String clsName = tableEntity.getClassName();
        List<String> files = new ArrayList<>();
        files.add(javaPackage + File.separator + p_controller + File.separator + clsName + "Controller.java");
        files.add(javaPackage + File.separator + p_entity + File.separator + clsName + ".java");
        files.add(javaPackage + File.separator + p_mapper + File.separator + clsName + "Mapper.java");
        files.add(resPackage + File.separator + p_mapper + File.separator + clsName + "Mapper.xml");
        files.add(javaPackage + File.separator + p_service + File.separator + "I" + clsName + "Service.java");
        files.add(javaPackage + File.separator + p_service + File.separator + "impl" + File.separator + clsName + "ServiceImpl.java");
        String frontDir = dataSource.getFrontDir();
        if ( frontDir != null && frontDir.length() > 0) {
            files.add(frontDir + File.separator + "src" + File.separator + "api" + File.separator + moduleName + File.separator + tableEntity.getLowClassName() + ".js");
            files.add(frontDir + File.separator + "src" + File.separator + "pages" + File.separator + moduleName + File.separator + tableEntity.getLowClassName() + ".vue");
        }

        // 模板 + 文件地址
        try {
            int len = files.size();
            byte[] buf = new byte[2 * 1024];
            for (int i = 0; i < len; i++) {
                String fileName = files.get(i);
                freemarkerTemp2File(tmps[i], map, fileName);
            }
            System.out.println("generator file:" + len);

            int length = 0;
            for (int j = 0; j < len; j++) {
                String fileName = files.get(j);
                File file = new File(fileName);
                zip.putNextEntry(new ZipEntry(fileName));
                System.out.println("generator in:" + fileName);
                FileInputStream in = new FileInputStream(file);
                while ((length = in.read(buf)) != -1) {
                    zip.write(buf, 0, len);
                }
                zip.closeEntry();
                in.close();
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e.getMessage());
        }
    }


    //生成bean
    public static void freemarkerTemp2File(String tempName, Map<String, Object> map, String file) throws Exception {

        File target = new File(file);
        if (!target.getParentFile().exists()) {
            target.getParentFile().mkdir();
        }
        Template temp = getTemplate(tempName);
        OutputStream fos = new FileOutputStream(target);
        Writer out = new OutputStreamWriter(fos);
        temp.process(map, out);
        fos.flush();
        fos.close();
    }

    /**
     * 列名转换成Java属性名
     */
    public static String columnToJava(String columnName) {
        return WordUtils.capitalizeFully(columnName, new char[]{'_'}).replace("_", "");
    }

    /**
     * 表名转换成Java类名
     */
    public static String tableToJava(String tableName, String tablePrefix) {
        if (StringUtils.isNotBlank(tablePrefix)) {
            tableName = tableName.replace(tablePrefix, "");
        }
        return columnToJava(tableName);
    }

    /**
     * 获取配置信息
     */
    public static Configuration getConfig() {
        try {
            return new PropertiesConfiguration("generator.properties");
        } catch (ConfigurationException e) {
            throw new RRException("获取配置文件失败，", e);
        }
    }

    public static Template getTemplate(String template) throws IOException, TemplateException {
        freemarker.template.Configuration cfg = new freemarker.template.Configuration(freemarker.template.Configuration.VERSION_2_3_28);
        String templatePath = GenUtils.class.getResource("/template/").getPath();
        // System.out.println("templatePath:" + templatePath);

        cfg.setDirectoryForTemplateLoading(new File(templatePath));
        cfg.setDefaultEncoding("UTF-8");
        cfg.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
        cfg.setLogTemplateExceptions(false);
        cfg.setWrapUncheckedExceptions(true);
        freemarker.template.Template temp = cfg.getTemplate(template);
        return temp;
    }

    /**
     * @param name    绝对路径
     * @param content 内容
     */
    public static void writeFile(String name, String content) {
        try {
            File writeFile = new File(name);
            File fold = writeFile.getParentFile();
            if (!fold.exists()) {
                fold.mkdir();
            }
            writeFile.createNewFile(); // 创建新文件,有同名的文件的话直接覆盖
            try (FileWriter writer = new FileWriter(writeFile);
                 BufferedWriter out = new BufferedWriter(writer)
            ) {
                out.write(content);
                out.flush(); // 把缓存区内容压入文件
            }
        } catch (IOException e) {
            System.out.println(name + "  >>> writeFile Fail");
            e.printStackTrace();
        }
    }


}
